class ChatsController < ApplicationController
  require 'rexml/document'
  before_filter :actualizar_last_seen_at, :only => "show"
  before_filter :ordenar_comprobar_usuarios, :only => "show"

  #Cargamos el hash de emoticonos, solo una vez al cargar la clase
  $emoticonos_disponibles = {":D" =>"sonrie.gif",":(" =>"triste.gif",":P" => "lengua.gif",";)" => "guinyo.gif", 
    "^_^" => "feliz.gif", "-_-" =>"dormido.gif", "¬¬" => "cejas.gif", ":S" => "mareado.gif",
    "XD" => "carcajada.gif", ":)" => "sonrisa.gif", "O_O" => "sorprendido.gif",
    "/ZZ" => "dormido.gif", "/??" => "cualo.gif" , "/SS" => "yonofui.gif", "/TD" =>"demonio.png",
    "/TR" => "regalo.png", "/TT" => "reloj.png", "/TP" => "tapa.png", "/TC" => "cine.png", 
    "/TU" => "tarta.png", "/TRES" => "plato.png"}

  def show
    if params[:new] #somos el que invita a un nuevo chat, por tanto borramos el anterior si existe
      crear_sobrescribir_xml(params[:id])
    else
      #Hacemos esto para hacer q el estado del nuevo usuario entrante salga antes, no tras una revision
      cambio_inicial_estado(current_usuario.login,@el_otro_usuario.login, params[:id])
    end
    render :layout => false
  end

  def crear_mensaje
    #abrimos archivo  y escribimos el nuevo mensaje
    @contenido = params[:mensaje][:texto]
    @contenido_tratado = tratar_texto(@contenido) #lo usamos para mostrar el mensaje en el template rjs
    @remitente = params[:usuario]
    unless @contenido.blank?
      begin
        #Abrimos como escritura, lo tengo que hacer así, no se insertar los elementos como lecturaq escritura, lo apuntamos para la v2
        fread = File.open( File.join(RAILS_ROOT, "registro_chat", "#{params[:id]}.xml"), "r")
        fread.flock(File::LOCK_EX)
        doc = REXML::Document.new(fread)
        fwrite = File.open( File.join(RAILS_ROOT, "registro_chat", "#{params[:id]}.xml"), "w")
        #modificamos fecha de ultimo_mensaje
        doc.root.attributes["fecha_ultimo_mensaje"] = Time.now.utc
        #añadimos el nuevo mensaje si no está vacío
        m = doc.root.add_element("mensaje", {"remitente" => @remitente, "visto" => false})
        doc.root.attributes["last_seen_at_#{params[:usuario]}"] = Time.now.utc
        m.add_text( @contenido )
        doc.write(fwrite,0)
      ensure
        fread.flock(File::LOCK_UN)
        fwrite.close
      end
    end
  end
 
  #TODO
  def mostrar_mensajes
    begin
      el_otro_login =  params[:el_otro] # es su login
      @mensajes = []
      fread = File.open( File.join(RAILS_ROOT, "registro_chat", "#{params[:id]}.xml"), "r")
      fread.flock(File::LOCK_EX)
      doc = REXML::Document.new(fread)
      fwrite = File.open( File.join(RAILS_ROOT, "registro_chat", "#{params[:id]}.xml"), "w")
      if nuevo_mensaje(doc)
        doc.root.each_element do |mensaje|
          if mensaje.attributes["remitente"] != params[:yo] and mensaje.attributes["visto"] == "false"
            mensaje.attributes["visto"] = true
            texto_tratado = tratar_texto(mensaje.text)
            @mensajes << [mensaje.attributes["remitente"], texto_tratado]
          end
        end  
      end
      #Actualizamos last_seen_at del chat del usuario actual
      doc.root.attributes["last_seen_at_#{params[:yo]}"] = Time.now.utc
      doc.write(fwrite,0)
    ensure
      fread.flock(File::LOCK_UN)
      fwrite.close  
    end
  end

  #métodos de solicitud y revision de peticiones de chat
  def solicitar_chat
    #aqui debemos crear un evento de nuevo chat para el usuario, asi como lanzarnos hacia el show del nuevo chat
    #buscamos si existe un chat abierto y los dos usuarios están dentro, si es así no lanzamos la notificacion
    if logged_in?
      chat_id = "#{current_usuario.login}-#{params[:amigo]}"
      if no_esta_chateando(chat_id, current_usuario.login) and no_esta_chateando(chat_id, params[:amigo])
        #lanzamos aviso y abrimos ventana
        amigo = Usuario.find_by_login(params[:amigo])
        evento_anterior = Evento.find_by_usuario_id_and_amigo_id_and_tipo(amigo.id, current_usuario.id, "chat")
        if evento_anterior 
          evento_anterior.update_attributes(:visto => false)
        elsif 
          Evento.create(:usuario_id => amigo.id, :amigo_id => current_usuario.id, :tipo => "chat")
        end
        redirect_to chat_path(:id => chat_id, :new =>true) and return
      elsif no_esta_chateando(chat_id, current_usuario.login)
        redirect_to chat_path(:id => chat_id, :new =>true) and return
      end
    end
    render :layout => false
  end

  def notificar_nuevo_chat
    #buscamos un nuevo evento de chat, si existe y no lo hemos lanzado antes llamamos a un callback javascript
    @evento_chat = Evento.find(:first, :conditions => ["visto = ? and usuario_id = ? and tipo = ?", false, current_usuario.id, "chat"])
    if @evento_chat
      #comprobar si el otro usuario está dentro del chat, a la hora de recibir la notificacion
      yo, el_otro = current_usuario.login, Usuario.find(@evento_chat.amigo_id).login
      @evento_chat.update_attributes(:visto => true)
      if no_esta_chateando("#{yo}-#{el_otro}", el_otro)
        @evento_chat = nil
      end    		
    end

  end

  def comprobar_actualizar_estado
    begin
      el_otro, yo, id_chat = params[:el_otro], params[:yo], params[:id]
      fread = File.open( File.join(RAILS_ROOT, "registro_chat", "#{params[:id]}.xml"), "r")
      fread.flock(File::LOCK_EX)
      doc = REXML::Document.new(fread)
      fwrite = File.open( File.join(RAILS_ROOT, "registro_chat", "#{params[:id]}.xml"), "w")
      #Comprobamos el estado del otro usuario
      #Vemos si ha cerrado la ventana
      if !dentro(el_otro, doc) and doc.root.attributes["estado_#{el_otro}"] == "dentro"
        cambiar_estado_a(doc, el_otro, "fuera")
      elsif doc.root.attributes["estado_#{el_otro}"] == "fuera"  #Vemos si no ha entrado y se ha desconectado
        el_otro_usuario = Usuario.find_by_login(el_otro)
        if !el_otro_usuario.conectado?
          cambiar_estado_a(doc, el_otro, "desconectado")
        end
      end 

      #miramos si hay alguna novedad
      if doc.root.attributes["estado_#{el_otro}_novedad"] == "true"
        case(doc.root.attributes["estado_#{el_otro}"])
        when("dentro")
          @notificacion = "<li class='notificacion_verde'>#{el_otro} ha entrado.</li>" 
        when("fuera")
          @notificacion = "<li class='notificacion_roja'>#{el_otro} ha cerrado el chat.</li>"
        when("desconectado") 
          @notificacion = "<li class='notificacion_roja'>#{el_otro} está desconectado.</li>"  
        when ("rechazado")
          @notificacion = "<li class='notificacion_roja'>#{el_otro} ha rechazado tu invitación.</li>"  
        end
        #poner novedad a false
        doc.root.attributes["estado_#{el_otro}_novedad"] = "false"
      end 

      #comprobamos mi propio estado
      if doc.root.attributes["estado_#{yo}"] == "fuera"
        cambiar_estado_a(doc, yo, "dentro")
      end

      doc.write(fwrite,0)
    ensure
      fread.flock(File::LOCK_UN)
      fwrite.close
      return @notificacion
    end
  end


  def rechazar_solicitud
    begin
      chat_id = params[:id]
      yo, el_otro = chat_id.split("-")
      #Reordenamos la posicion de los nombres pues, solo existe una distribucion de nombres
      chat_id = "#{el_otro}-#{yo}" if (yo <=> el_otro) == -1
      fread = File.open( File.join(RAILS_ROOT, "registro_chat", "#{chat_id}.xml"), "r")
      fread.flock(File::LOCK_EX)
      doc = REXML::Document.new(fread)
      cambiar_estado_a(doc, yo, "rechazado")
      fwrite = File.open( File.join(RAILS_ROOT, "registro_chat", "#{chat_id}.xml"), "w")
      doc.write(fwrite,0)
    ensure
      fread.flock(File::LOCK_UN)
      fwrite.close
    end
    redirect_to :back
  end

  protected

  def crear_sobrescribir_xml(chat_id)
    #creamos o sobrescribimos el archivo xml correspondiente
    f = File.open( File.join(RAILS_ROOT, "registro_chat", "#{chat_id}.xml"), "w")
    #creamos base xml, root, y atributos
    doc = REXML::Document.new
    root = doc.add_element( "chat", {"estado_#{current_usuario.login}_novedad" => true,
    "estado_#{current_usuario.login}" => "dentro",
    "estado_#{@el_otro_usuario.login}_novedad" => false,
    "estado_#{@el_otro_usuario.login}" => "fuera",
    "fecha_ultimo_mensaje" => Time.now.utc,
    "last_seen_at_#{current_usuario.login}" => Time.now.utc,
    "last_seen_at_#{@el_otro_usuario.login}" => Time.now.utc})
    doc.write(f,0)
    f.close
  end

  def ordenar_comprobar_usuarios #el orden de los usuarios iran de menor a mayor
    usuario1, usuario2 = params[:id].split("-")
    if ((current_usuario.login == usuario1) or (current_usuario.login == usuario2)) and (usuario1 != usuario2)
      if usuario1 == current_usuario.login
        @el_otro_usuario = Usuario.find_by_login(usuario2)
      else
        @el_otro_usuario = Usuario.find_by_login(usuario1)
      end
      comparacion = usuario1 <=> usuario2
      if comparacion == -1  
        redirect_to chat_path(:id => "#{usuario2}-#{usuario1}", :new => params[:new]) and return
      end
    else #usuario que kiere accedeq a un chat que no lo corresponde
      redirect_to main_path
      flash[:error] = "No juegues con eso ¬¬"
    end
  end

  def nuevo_mensaje(doc_xml)
    return doc_xml.root.attributes["fecha_ultimo_mensaje"] > (Time.now - 8.seconds).utc.to_s
  end
  
  def dentro(usuario_login, doc_xml)
    return doc_xml.root.attributes["last_seen_at_#{usuario_login}"] > (Time.now - 10.seconds).utc.to_s
  end

  def no_esta_chateando(chat_id, usuario)
    #Buscamos si ya existe el chat, y si está el otro dentro
    yo, el_otro = chat_id.split("-")
    #Reordenamos la posicion de los nombres pues, solo existe una distribucion de nombres
    chat_id = "#{el_otro}-#{yo}" if (yo <=> el_otro) == -1
    if File.exists?(File.join(RAILS_ROOT,"registro_chat", "#{chat_id}.xml")) 
      f = File.open( File.join(RAILS_ROOT, "registro_chat", "#{chat_id}.xml"), "r")
      f.flock(File::LOCK_EX)
      doc = REXML::Document.new(f)
      f.flock(File::LOCK_UN)
      f.close
      return !dentro(usuario, doc)
    end
    return true
  end

  def cambiar_estado_a(doc, login_usuario, estado)
    doc.root.attributes["estado_#{login_usuario}"] = estado
    doc.root.attributes["estado_#{login_usuario}_novedad"] = "true"
  end

  def cambio_inicial_estado(usuario, el_otro, id_chat)
    fread = File.open( File.join(RAILS_ROOT, "registro_chat", "#{id_chat}.xml"), "r")
    fread.flock(File::LOCK_EX)
    doc = REXML::Document.new(fread)
    fwrite = File.open( File.join(RAILS_ROOT, "registro_chat", "#{id_chat}.xml"), "w")

    cambiar_estado_a(doc, usuario, "dentro")
    doc.root.attributes["last_seen_at_#{usuario}"] = Time.now.utc
    doc.root.attributes["estado_#{el_otro}_novedad"] = "false"
    doc.write(fwrite,0)
    fread.flock(File::LOCK_UN)
    fwrite.close
  end

  def tratar_texto(texto)
    texto_escapado = CGI::escapeHTML(texto) #Quitamos elementos peligrosos :pL
    palabras = texto_escapado.split(" ")
    res = ""

    palabras.each do |palabra|
      if $emoticonos_disponibles.keys.include?(palabra.upcase)
        imagen = $emoticonos_disponibles[palabra.upcase]
        res << "<image src='/images/emoticonos/#{[imagen]}' alt='#{palabra}'/>"
      elsif palabra =~ /^(w{3}\.|((ftp|https?):\/\/))([-a-z0-9]+\.)+[a-z]{2,}/
        res << "<a href='http://#{palabra}' target='_blank'>#{palabra}</a> " if palabra =~ /^w{3}\./
        res << "<a href='#{palabra}' target='_blank'>#{palabra}</a> " if palabra =~/^((ftp|https?):\/\/)/
      else
        res << palabra + " "
      end
    end
    return res
  end

end
